<script setup lang="ts">
import type { PropType } from "vue";
import { computed, watch } from "vue";

defineOptions({
  name: "ByRadio",
});

const props = defineProps({
  // v-model绑定值
  modelValue: {
    type: [String, Number, Boolean],
    default: "",
  },
  // 数据列表
  options: {
    type: Array as PropType<any>,
    default: () => [],
  },
  // 是否按钮样式
  isButton: {
    type: Boolean,
    default: false,
  },
  // 是否带有边框
  border: {
    type: Boolean,
    default: false,
  },
  // 组件尺寸
  size: {
    type: String,
    default: "default",
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
  // value的字段名
  valueKey: {
    type: String,
    default: "id",
  },
  // label的字段名
  labelKey: {
    type: [String, Function],
    default: "label",
  },
  // 是否显示全部选项
  firstAll: {
    type: Boolean,
    default: false,
  },
  filterMethod: {
    type: Function,
    default: null,
  },
  hiddenIcon: {
    type: Boolean,
    default: false,
  },
  autoSetDefaultValue: {
    type: Boolean,
    default: true,
  },
});

const emit = defineEmits(["update:modelValue", "change"]);

// 计算后的选项列表,添加全部选项
const filterData = computed(() => {
  if (props.filterMethod) {
    return props.filterMethod(props.options) || [];
  }
  return props.options;
});

const computedOptions = computed(() => {
  if (!props.firstAll) return filterData.value;
  const allOption = {
    [props.valueKey]: "",
    [props.labelKey]: "全部",
  };
  return [allOption, ...filterData.value];
});
const handleUpdate = (value) => {
  emit("update:modelValue", value);
};
// 选项改变事件
const handleChange = (value) => {
  emit("change", value);
};
// 当选项列表改变时,重置modelValue为''
watch(
  () => filterData.value,
  (newVal, oldVal) => {
    if (!props.autoSetDefaultValue) return;
    let isZero =
      newVal.length == 0 ||
      oldVal.length == 0 ||
      newVal.length !== oldVal.length;
    let changeValue = isZero
      ? true
      : newVal[0][props.valueKey] !== oldVal[0][props.valueKey];
    if (isZero || changeValue) {
      const defaultValue = computedOptions.value[0]?.[props.valueKey];
      emit("update:modelValue", defaultValue);
    }
  },
  { deep: true }
);
const getLabel = (item) => {
  if (item) {
    let labelKey = props.labelKey;
    if (typeof labelKey === "function") return labelKey(item);
    return item[labelKey];
  }
};
</script>

<template>
  <div class="by-radio">
    <template v-if="$slots.prefix">
      <slot name="prefix" />
    </template>
    <el-radio-group
      :model-value="modelValue"
      @update:model-value="handleUpdate"
      :size="size"
      :class="{ 'hidden-icon': hiddenIcon }"
      @change="handleChange"
      :disabled="disabled"
    >
      <template v-if="isButton">
        <el-radio-button
          v-for="item in computedOptions"
          :key="item[valueKey]"
          :value="item[valueKey]"
          :disabled="item.disabled"
        >
          <slot name="default" :row="item">
            {{ getLabel(item) }}
          </slot>
        </el-radio-button>
      </template>
      <template v-else>
        <el-radio
          v-for="item in computedOptions"
          :key="item[valueKey]"
          :value="item[valueKey]"
          :border="border"
          :disabled="item.disabled"
        >
          <slot name="default" :row="item">
            {{ getLabel(item) }}
          </slot>
        </el-radio>
      </template>
    </el-radio-group>
  </div>
</template>

<style scoped lang="scss">
.hidden-icon {
  :deep(.el-radio__input) {
    display: none;
  }

  :deep(.el-radio) {
    margin-right: 20px;
  }

  :deep(.el-radio__label) {
    font-size: 15px;
    font-weight: 600;
    padding-left: 0;

    // padding: 0 4px;
    &:hover {
      color: var(--el-color-primary);
    }
  }
}
</style>
